{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Tutorial: As Ferramentas Básicas do Private Deep Learning\n",
    "\n",
    "Seja bem-vindo ao tutorial do PySyft sobre proteção de privacidade e deep learning descentralizado. Esta série de notebooks é um guia passo a passo para você conhecer as novas ferramentas e técnicas necessárias para deep learning em dados/modelos secretos/privados sem centralizá-los sob uma única autoridade.\n",
    "\n",
    "Escopo: Observe que não falaremos apenas sobre como descentralizar / criptografar dados, mas abordaremos como o PySyft pode ser usado para ajudar a descentralizar todo o ecossistema em torno dos dados, incluindo os bancos de dados onde os dados são armazenados e consultados, e os modelos neurais que são usados para extrair informações dos dados. À medida que novas extensões ao PySyft são criadas, esses notebooks serão estendidos com novos tutoriais para explicar a nova funcionalidade.\n",
    "\n",
    "Autores:\n",
    "\n",
    "- Andrew Trask - Twitter: [@iamtrask](https://twitter.com/iamtrask)\n",
    "\n",
    "Tradução:\n",
    "\n",
    "- Márcio Porto - GitHub: [@MarcioPorto](https://github.com/MarcioPorto/)\n",
    "\n",
    "## Esboço:\n",
    "\n",
    "- Parte 1: As Ferramentas Básicas do Private Deep Learning\n",
    "\n",
    "\n",
    "## Por que fazer este tutorial?\n",
    "\n",
    "**1) Uma vantagem competitiva na sua carreira** - Nos últimos 20 anos, a revolução digital tornou dados cada vez mais acessíveis em quantidades cada vez maiores à medida que os processos analógicos foram digitalizados. No entanto, com novos regulamentos, como o [GDPR](https://eugdpr.org/), as empresas estão sob pressão para ter menos liberdade na maneira como usam - e principalmente na maneira como analisam - informações pessoais. **Conclusão:** Os cientistas de dados não terão acesso a tantos dados com as ferramentas antigas, mas aprendendo as ferramentas do Private Deep Learning, VOCÊ poderá estar à frente dessa curva e ter uma vantagem competitiva em sua carreira.\n",
    "\n",
    "**2) Oportunidades de empreendorismo** - Há uma série de problemas na sociedade que o Deep Learning pode resolver, mas muitos dos problemas mais importantes não estão sendo explorados porque exigiriam acesso a informações incrivelmente sensíveis sobre as pessoas (como usar o Deep Learning para ajudar pessoas com problemas mentais ou de relacionamento!). Assim, o aprendizado do Private Deep Learning libera uma série de novas oportunidades de startup para você, que não estavam disponíveis anteriormente para outras pessoas sem esse conhecimento.\n",
    "\n",
    "**3) Bem Social** - O Deep Learning pode ser usado para resolver uma ampla variedade de problemas no mundo real, mas é importante lembrar que  Deep Learning em *informações pessoais* é Deep Learning sobre pessoas, *para pessoas*. Aprender a aplicar Deep Learning em dados que você não possui representa mais do que uma oportunidade de carreira ou de empreendorismo; é uma oportunidade de ajudar a resolver alguns dos problemas mais pessoais e importantes da vida de várias pessoas.\n",
    "\n",
    "## Como obtenho crédito extra?\n",
    "\n",
    "- Aperte \"Star\" no repositório do PySyft no GitHub! - [https://github.com/OpenMined/PySyft](https://github.com/OpenMined/PySyft)\n",
    "- Faça um vídeo no YouTube ensinando este notebook!\n",
    "\n",
    "\n",
    "... ok ... vamos lá!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Parte -1: Pré-requisitos\n",
    "\n",
    "- Conhecimento do PyTorch - se não tiver experiência com PyTorch, faça o curso http://fast.ai e volte para este tutorial.\n",
    "- Leia o documento técnico do PySyft https://arxiv.org/pdf/1811.04017.pdf! Isso fornecerá um histórico completo de como o PySyft foi construído, o que ajudará este tutorial fazer mais sentido."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Parte 0: Configuração\n",
    "\n",
    "Para começar, você precisará instalar algumas coisas. Para fazer isso, vá para o README do PySyft e siga as instruções de configuração. Resumindo:\n",
    "\n",
    "- Instale o Python 3.6 ou superior\n",
    "- Instale o PyTorch 1.3\n",
    "- Clone o PySyft (git clone https://github.com/OpenMined/PySyft.git)\n",
    "- cd PySyft\n",
    "- pip install -r pip-dep/requirements.txt\n",
    "- pip install -r pip-dep/requirements_udacity.txt\n",
    "- python setup.py install udacity\n",
    "- python setup.py test\n",
    "\n",
    "Se alguma dessas instruções não funcionar para você (ou algum dos testes falhar) - verifique primeiro o [README](https://github.com/OpenMined/PySyft.git) para obter ajuda sobre a instalação e, em seguida, abra um issue no GitHub ou entre em contato pelo canal #beginner no nosso Slack! [slack.openmined.org](http://slack.openmined.org/)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Execute esta célula para conferir que tudo está funcionando\n",
    "import sys\n",
    "\n",
    "import torch\n",
    "from torch.nn import Parameter\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "import syft as sy\n",
    "hook = sy.TorchHook(torch)\n",
    "\n",
    "torch.tensor([1,2,3,4,5])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Se esta célula for executada, você estará pronto para continuar! Vamos lá!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Parte 1: As Ferramentas Básicas da Ciência de Dados Privada e Descentralizada\n",
    "\n",
    "Então, a primeira coisa que você deve estar se perguntando é: como  treinamos um modelo de dados aos quais não temos acesso?\n",
    "\n",
    "Bem, a resposta é surpreendentemente simples. Se você está acostumado a trabalhar com PyTorch, está acostumado a trabalhar com objetos torch.Tensor como estes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = torch.tensor([1,2,3,4,5])\n",
    "y = x + x\n",
    "print(y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Obviamente, usar esses tensores super sofisticados (e poderosos!) é importante, mas também exige que você tenha os dados em sua máquina local. É aqui que a nossa jornada começa.\n",
    "\n",
    "# Seção 1.1 - Enviando tensores para a máquina de Bob\n",
    "\n",
    "Apesar de normalmente fazermos ciência de dados / deep learning na máquina que contém os dados, agora queremos realizar esse tipo de computação em alguma **outra** máquina. Mais especificamente, não podemos mais simplesmente assumir que os dados estão em nossa máquina local.\n",
    "\n",
    "Assim, em vez de usar os tensores do Torch, agora vamos trabalhar com **apontadores** para os tensores. Deixe-me mostrar o que eu quero dizer. Primeiro, vamos criar uma máquina de \"fingir\" pertencente a uma pessoa fictícia - vamos chamá-lo de Bob."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bob = sy.VirtualWorker(hook, id=\"bob\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Digamos que a máquina de Bob esteja em outro planeta - talvez em Marte! Mas, no momento, a máquina está vazia. Vamos criar alguns dados para que possamos enviá-los a Bob e aprender sobre apontadores!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = torch.tensor([1,2,3,4,5])\n",
    "y = torch.tensor([1,1,1,1,1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "E agora - vamos enviar nossos tensores para Bob!!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_ptr = x.send(bob)\n",
    "y_ptr = y.send(bob)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_ptr"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "BOOM! Agora Bob tem dois tensores! Não acredita em mim? Dê uma olhada abaixo!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bob._objects"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z = x_ptr + x_ptr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bob._objects"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Agora observe algo. Quando chamamos `x.send(bob)`, recebemos um novo objeto que chamamos de `x_ptr`. Este é o nosso primeiro *apontador* para um tensor. Os apontadores para tensores NÃO mantêm os próprios dados. Em vez disso, eles simplesmente contêm metadados sobre um tensor (com dados) armazenados em outra máquina. O objetivo desses tensores é fornecer uma API intuitiva para instruir a outra máquina a calcular funções usando esse tensor. Vamos dar uma olhada nos metadados que os apontadores contêm."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_ptr"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Confira esses metadados!\n",
    "\n",
    "Existem dois atributos principais específicos para apontadores:\n",
    "\n",
    "- `x_ptr.location : bob`, o local, uma referência ao local para o qual o apontador está apontando\n",
    "- `x_ptr.id_at_location : <número inteiro aleatório>`, o ID em que o tensor está armazenado no local\n",
    "\n",
    "Eles são impressos no formato `<ID no local>@<local>`\n",
    "\n",
    "Há também outros atributos mais genéricos:\n",
    "- `x_ptr.id : <número inteiro aleatório>`, o ID do nosso apontador de tensor, que foi alocado aleatoriamente\n",
    "- `x_ptr.owner : \"me\"`, o worker que possui o apontador de tensor, que neste caso é o worker local, chamado \"me\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_ptr.location"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bob"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bob == x_ptr.location"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_ptr.id_at_location"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_ptr.owner"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Você pode se perguntar por que o worker local que possui o apontador também é um VirtualWorker, embora não o tenhamos criado.\n",
    "Curiosamente, assim como tínhamos um objeto VirtualWorker para Bob, nós (automaticamente) sempre temos um para nós também. Este worker é criado assim que chamamos `hook = sy.TorchHook()` e, portanto, você normalmente não precisa criá-lo."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "me = sy.local_worker\n",
    "me"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "me == x_ptr.owner"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "E finalmente, assim como podemos chamar .send() em um tensor, podemos chamar .get() em um apontador para recuperar um tensor!!!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_ptr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_ptr.get()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_ptr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_ptr.get()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z.get()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bob._objects"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "E como você pode ver... Bob não tem mais os tensores!!! Eles voltaram para a nossa máquina!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Seção 1.2 - Usando apontadores para tensores\n",
    "\n",
    "Então, enviar e receber tensores de Bob é ótimo, mas isso dificilmente pode ser considerado Deep Learning! Queremos ser capazes de executar _operações_ em tensores remotos. Felizmente, os apontadores para tensores tornam isso bastante fácil! Você pode simplesmente usar apontadores como usaria tensores normais!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = torch.tensor([1,2,3,4,5]).send(bob)\n",
    "y = torch.tensor([1,1,1,1,1]).send(bob)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z = x + y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "E voilà!\n",
    "\n",
    "Nos bastidores, algo muito poderoso aconteceu. Em vez de x e y computarem uma adição localmente, um comando foi serializado e enviado a Bob, que executou a computação, criou um tensor z e, em seguida, retornou o apontador para z de volta para nós!\n",
    "\n",
    "Se chamarmos .get() no apontador, receberemos o resultado de volta à nossa máquina!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z.get()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Funções do Torch\n",
    "\n",
    "Esta API suporta todas as operações do Torch!!!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z = torch.add(x,y)\n",
    "z"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z.get()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Variáveis (incluindo backpropagation!)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = torch.tensor([1,2,3,4,5.], requires_grad=True).send(bob)\n",
    "y = torch.tensor([1,1,1,1,1.], requires_grad=True).send(bob)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z = (x + y).sum()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z.backward()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = x.get()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x.grad"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Como você pode ver, a API é realmente bastante flexível e capaz de executar praticamente qualquer operação que você normalmente executaria no Torch em *dados remotos*. Isso estabelece a base para nossos protocolos mais avançados de preservação de privacidade, como Federated Learning, Computação Multipartidária Segura (SMPC - Secure Multipart Computation) e Privacidade Diferencial!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Parabéns!!! - Hora de se juntar a comunidade!\n",
    "\n",
    "Parabéns por concluir esta etapa do tutorial! Se você gostou e gostaria de se juntar ao movimento em direção à proteção de privacidade, propriedade descentralizada e geração, demanda em cadeia, de dados em IA, você pode fazê-lo das seguintes maneiras!\n",
    "\n",
    "### Dê-nos uma estrela em nosso repo do PySyft no GitHub\n",
    "\n",
    "A maneira mais fácil de ajudar nossa comunidade é adicionando uma estrela nos nossos repositórios! Isso ajuda a aumentar a conscientização sobre essas ferramentas legais que estamos construindo.\n",
    "\n",
    "- [Star PySyft](https://github.com/OpenMined/PySyft)\n",
    "\n",
    "### Junte-se ao Slack!\n",
    "\n",
    "A melhor maneira de manter-se atualizado sobre os últimos avanços é se juntar à nossa comunidade! Você pode fazer isso preenchendo o formulário em [http://slack.openmined.org](http://slack.openmined.org)\n",
    "\n",
    "### Contribua com o projeto!\n",
    "\n",
    "A melhor maneira de contribuir para a nossa comunidade é se tornando um contribuidor do código! A qualquer momento, você pode acessar a página de *Issues* (problemas) do PySyft no GitHub e filtrar por \"Projetos\". Isso mostrará todas as etiquetas de nível superior, com uma visão geral de quais projetos você pode participar! Se você não deseja ingressar em um projeto, mas gostaria de codificar um pouco, também pode procurar mais mini-projetos \"independentes\" pesquisando problemas no GitHub marcados como \"good first issue\".\n",
    "\n",
    "- [Projetos do PySyft](https://github.com/OpenMined/PySyft/issues?q=is%3Aopen+is%3Aissue+label%3AProject)\n",
    "- [Etiquetados como Good First Issue](https://github.com/OpenMined/PySyft/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)\n",
    "\n",
    "### Doar\n",
    "\n",
    "Se você não tem tempo para contribuir com nossa base de códigos, mas ainda deseja nos apoiar, também pode se tornar um Apoiador em nosso Open Collective. Todas as doações vão para hospedagem na web e outras despesas da comunidade, como hackathons e meetups!\n",
    "\n",
    "[Página do Open Collective do OpenMined](https://opencollective.com/openmined)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
